$ bin/standalone.sh -c=standalone.xml
ModeShape is not included with JBoss EAP, so none of the standard configurations include any ModeShape configurations. However, once ModeShape is installed into EAP, it's easy to add ModeShape to any AS7 configuration.
If you need to run ModeShape 3.0.x or 3.1, then these instructions apply to configuring ModeShape in AS7.1.1.
Start your server in standalone mode with your favorite configuration. For example, the following starts with the "standalone.xml" configuration file:
$ bin/standalone.sh -c=standalone.xml
Use the appropriate command for your OS. See the EAP documentation (or AS7 documentation) for details.
JBoss EAP has a very nice low-level command line interface (CLI) tool that you can use to directly manipulate the configuration of the running server. If the server is running in domain mode, the CLI will immediately propagate the changes to all the servers.
Start the CLI and connect to your server:
$ ./bin/jboss-cli.sh You are disconnected at the moment. Type 'connect' to connect to the server or 'help' for the list of supported commands. [disconnected /] connect [standalone@localhost:9999 /]
ModeShape is installed, but the current configuration doesn't know about the ModeShape subsystem. So the next step is to add it:
[standalone@localhost:9999 /] /extension=org.modeshape:add() {"outcome" => "success"} [standalone@localhost:9999 /] ./subsystem=modeshape:add {"outcome" => "success"}
The configuration's XML file (in this case "standalone.xml") is updated immediately. Watch the configuration file as you use the CLI.
We want to add a repository, but before we do that we need to add or configure the EAP resources that the repository will use.
Each ModeShape repository stores its content in an Infinispan cache. But let's put that cache in a new cache container named "modeshape", which we can use for other repositories:
[standalone@localhost:9999 /] /subsystem=infinispan/cache-container=modeshape:add {"outcome" => "success"}
The CLI supports tab-completion, so as you type out these paths try hitting tab to have the CLI fill out as much as possible or show the available matches.
Now that we have our container, we'll define a local cache named "sample" (which by convention we'll name the same as our repository, although this is not required) that uses non-XA transactions and persists all content immediately to the "modeshape/store/sample" directory under the "standalone/data" directory:
[standalone@localhost:9999 /] /subsystem=infinispan/cache-container=modeshape/local-cache=sample:add {"outcome" => "success"} [standalone@localhost:9999 /] /subsystem=infinispan/cache-container=modeshape/local-cache=sample/transaction=TRANSACTION:add(mode=NON_XA) { "outcome" => "success", "response-headers" => { "operation-requires-reload" => true, "process-state" => "reload-required" } } [standalone@localhost:9999 /] /subsystem=infinispan/cache-container=modeshape/local-cache=sample/file-store=FILE_STORE:add(path="modeshape/store/sample",relative-to="jboss.server.data.dir",passivation=false,purge=false) { "outcome" => "success", "response-headers" => {"process-state" => "reload-required"} }
Most of the commands we've issued so far resulted in a simple successful outcome. The last two, however, were successful but apparently require a reload of the Infinispan service. That basically means that our changes were saved to the configuration, but the last two changes won't take effect until the next restart or until we explicitly perform the reload (which we'll do twice):
[standalone@localhost:9999 /] :reload { "outcome" => "success", "response-headers" => {"process-state" => "reload-required"} } [standalone@localhost:9999 /] :reload {"outcome" => "success"}
ModeShape can use any security domain, as long as the domain defines the correct ModeShape roles for each user. Since none of the out-of-the-box security domains includes these roles, let's create our own security domain that uses the modeshape-users.properties and modeshape-roles.properties files included in the "module/org/modeshape/main/conf" directory:
[standalone@localhost:9999 /] ./subsystem=security/security-domain=modeshape-security:add(cache-type=default) {"outcome" => "success"} [standalone@localhost:9999 /] ./subsystem=security/security-domain=modeshape-security/authentication=classic:add(login-modules=[{"code"=>"UsersRoles","flag"=>"required","module-options"=>[("usersProperties"=>"modeshape-users.properties"),("rolesProperties"=>"modeshape-roles.properties")]}]) { "outcome" => "success", "response-headers" => { "operation-requires-reload" => true, "process-state" => "reload-required" } }
Again, we need to reload the services for these changes to take effect:
[standalone@localhost:9999 /] :reload { "outcome" => "success", "response-headers" => {"process-state" => "reload-required"} } [standalone@localhost:9999 /] :reload {"outcome" => "success"}
JBoss EAP supports multiple kinds of security domains, including integration with LDAP and even single sign-on using the local OS. Consult the JBoss AS documentation for details.
Now that we've finished defining the services that our repository will use, we can define our ModeShape "sample" repository:
[standalone@localhost:9999 /] ./subsystem=modeshape/repository=sample:add(security-domain="modeshape-security",cache-name="sample",cache-container="modeshape") {"outcome" => "success"}
This command configures the repository to use the "sample" Infinispan cache in the "modeshapce" cache container, and to use the "modeshape-security" security domain we created earlier.
We actually didn't need to define the security-domain="modeshape-security" attribute because the repository would use a security domain with that name by default. Also, by default the repository will try to use an Infinispan cache with the same name as the repository in the cache container named "modeshape". Specifying them doesn't hurt, but any attributes that match the default value will not be serialized to the XML configuration file.
Note that defining a repository doesn't require restart. In fact, quite a few of the ModeShape administrative operations can take effect immediately, even when applications are actively using the repository.
With just a few commands, you can add a repository that will persist content locally. However, more advanced configuration options are available.
At any point, we can see the complete definition of a repository:
[standalone@localhost:9999 /] /subsystem=modeshape/repository=sample:read-resource(recursive=true) { "outcome" => "success", "result" => { "allow-workspace-creation" => true, "anonymous-roles" => undefined, "anonymous-username" => "<anonymous>", "binary-storage" => undefined, "cache-container" => "modeshape", "cache-name" => "sample", "cluster-name" => undefined, "cluster-stack" => undefined, "default-workspace" => "default", "enable-monitoring" => true, "index-storage" => undefined, "indexing-analyzer-classname" => "org.apache.lucene.analysis.standard.StandardAnalyzer", "indexing-analyzer-module" => undefined, "indexing-async-max-queue-size" => 0, "indexing-async-thread-pool-size" => 1, "indexing-batch-size" => -1, "indexing-mode" => "SYNC", "indexing-reader-strategy" => "SHARED", "indexing-thread-pool" => "modeshape-workers", "jndi-name" => undefined, "minimum-binary-size" => 4096, "predefined-workspace-names" => undefined, "rebuild-indexes-upon-startup" => "IF_MISSING", "security-domain" => "modeshape-security", "sequencer" => undefined, "use-anonymous-upon-failed-authentication" => false } }
This shows all of the attributes, including those that are not set or set to their default values. To see more detail about each attribute and child, use the ":read-resource-description()" command:
[standalone@localhost:9999 /] /subsystem=modeshape/repository=sample:read-resource-description(recursive=true) { "outcome" => "success", "result" => { "description" => "ModeShape repository", "attributes" => { "cache-name" => { "type" => STRING, "description" => "The name of the Infinispan cache that is to be used for storing this repository's content", "expressions-allowed" => false, "nillable" => true, "min-length" => 1L, "max-length" => 2147483647L, "access-type" => "read-write", "storage" => "configuration", "restart-required" => "resource-services" }, "cache-container" => { "type" => STRING, "description" => "The name of the Infinispan cache container that contains the cache to be used for storing this repoitory's content", "expressions-allowed" => false, "nillable" => true, "min-length" => 1L, "max-length" => 2147483647L, "access-type" => "read-write", "storage" => "configuration", "restart-required" => "resource-services" }, "jndi-name" => { "type" => STRING, "description" => "The optional alias in JNDI where this repository is to be registered, in addition to 'jcr/{repositoryName}", "expressions-allowed" => false, "nillable" => true, "min-length" => 1L, "max-length" => 2147483647L, "access-type" => "read-write", "storage" => "configuration", "restart-required" => "resource-services" }, ...
We didn't show all of the output, since it's quite long. But each attribute is described and shows the criteria for valid values, whether expressions (e.g., system variables) are allowed, and whether a restart will be required before changes take effect.
Most of the attributes do have defaults, but some of these defaults are not listed in the descriptions because the defaults are functions of other attributes. For example, every repository is registered in JNDI under "jcr/repositoryName", and also under the JNDI name explicitly set with the "jndi-name" attribute.
The following table contains the list of all the attributes for a repository:
Attribute Name |
Description |
allow-workspace-creation |
Specifies whether authenticated and authorized JCR users can create additional workspaces beyond the predefined, system, and default workspaces. The default value is 'true'. Set this to 'false' when the workspaces are to be fixed. |
anonymous-roles |
The list of string names of the roles for all anonymous users. Anonymous logins will be disabled if the roles consists of an empty string. By default, anonymous users are given all roles: 'connect', 'readonly', 'readwrite', and 'admin'. |
anonymous-username |
The username for all anonymous users. The username '<anonymous>' is used by default (that is, 'anonymous' surrounded by angle brackets"). |
cache-container |
The name of the Infinispan cache container in which the cache can be found. If not provided, the "modeshape" cache container will be used. |
cache-name |
The name of the Infinispan cache where repository content will be stored.If not provided, the repository name is used for the cache name. |
cluster-name |
Defines the name of the communication channel used to share events amongst all repository instances in the cluster. By default there is no value, meaning the repository is not participating in a cluster. |
cluster-stack |
Specifies the name of the JGroups stack used by the repository to create a channel for events when the repository is clustered. By default there is no value, meaning the repository is not participating in a cluster. |
default-workspace |
The name of the workspace that should be used when Sessions are created without specifying an explicit workspace name. By default, the "default" workspace name is used. |
enable-monitoring |
Specifies whether the repository is to maintain the metrics that can be used to monitor the performance and activities. The default value is 'true', meaning monitoring is enabled. |
indexing-analyzer-classname |
The fully-qualified name of the Lucene analyzer implementation class. The default value is 'org.apache.lucene.analysis.standard.StandardAnalyzer'. |
indexing-analyzer-module |
The name of the module that contains the specified analyzer class. No value is specified by default, which means the class is visible to the ModeShape engine (e.g., or any of its transitive dependencies). |
indexing-async-max-queue-size |
The maximum size of the queue used for asynchronous indexing. By default the value is '0'. The value is ignored if synchronous indexing is enabled. |
indexing-async-thread-pool-size |
The size of the thread pool used for asynchronous indexing. By default the value is '1'. The value is ignored if synchronous indexing is enabled. |
indexing-batch-size |
The size of the indexing batches. The default value is -1, which means the batch sizes are unlimited. |
indexing-mode |
The concurrency mode for indexing. The value must be either 'SYNC' or 'ASYNC'. |
indexing-reader-strategy |
The strategy for sharing (or not sharing) index readers. The value must be either 'SHARED' or 'NOT_SHARED'. |
indexing-thread-pool |
The name of the thread pool that the repository indexing system should use. By default, the value is 'modeshape-workers'. |
jndi-name |
The repository will always be bound in JNDI to the name 'jcr/{repositoryName}', but this attribute can be used to specify an additional location in JNDI where the repository is to be registered. |
minimum-binary-size |
The size threshold that dictates whether String and binary values should be stored in the binary store. String and binary values smaller than this value are stored with the node, whereas string and binary values with a size equal to or greater than this limit will be stored separately from the node and in the binary store, keyed by the SHA-1 hash of the value. This is a space and performance optimization that stores each unique large value only once. The default value is '4096' bytes, or 4 kilobytes. |
predefined-workspace-names |
The names of the workspaces that the repository will ensure exist (or create if necessary) when the repository starts up. |
rebuild-indexes-upon-startup |
Specifies whether the indexes need to be rebuilt immediately when each ModeShape process starts up. Must be one of 'IF_MISSING' , 'ALWAYS' or 'NEVER. By default it is 'IF_MISSING' |
rebuild-upon-startup-mode |
Specifies the way in which index rebuilding at startup should be performed: synchronously and asynchronously. Must be one of 'SYNC' or 'ASYNC'. By default it is 'SYNC' |
rebuild-upon-startup-include-system-content |
Specifies if, when rebuilding indexes at startup, the system content area (the nodes below /jcr:system) should be indexed or not. By default it is 'FALSE' |
security-domain |
The name of the security domain that should be used for JAAS authentication. The default is 'modeshape-security' |
use-anonymous-upon-failed-authentication |
Indicates that failed authentication attempts will not result in a javax.jcr.LoginException but will instead fall back to anonymous access. If anonymous access is not enabled, then failed login attempts will throw a LoginException. The default value is 'false'. |
default-initial-content |
The file which should be treated as the default initial content imported into all workspace. See initial content for more information |
workspaces-initial-content |
A set of (workspaceName, initial content file) pairs, which defined the custom initial content files for each workspace. See initial content for more information |
node-types |
A sequence of node-type elements, where the value of each element represents a path to a CND file which should be imported at repository startup. See registering custom node types for more information |
external-sources |
A sequence of source elements, where each element contains the definition of an external source |
At this point, any deployed application can use the repository (see the the chapter) for details).
You can use the CLI to dynamically add and remove sequencers. Here's an example that adds to the "sample" repository a sequencer that operates against comma-separated value (CSV) files uploaded under the "/files" node:
[standalone@localhost:9999 /] /subsystem=modeshape/repository=sample/sequencer=delimited-text-sequencer:add( classname="org.modeshape.sequencer.text.DelimitedTextSequencer", module="org.modeshape.sequencer.text", path-expressions=["/files(//*.csv[*])/jcr:content[@jcr:data] => /derived/text/delimited/$1"], properties=[{ "splitPattern"=>"," }]) {"outcome" => "success"} [standalone@localhost:9999 /] /subsystem=modeshape/repository=sample/sequencer=delimited-text-sequencer:read-resource() { "outcome" => "success", "result" => { "classname" => "org.modeshape.sequencer.text.DelimitedTextSequencer", "module" => "org.modeshape.sequencer.text", "path-expressions" => ["/files(//*.csv[*])/jcr:content[@jcr:data] => /derived/text/delimited/$1"], "properties" => [{"splitPattern" => ","}] } }
Note how this particular sequencer has an additional "splitPattern" property that specifies the delimiter.
To remove a sequencer, simply invoke the "remove" operation on the appropriate item:
[standalone@localhost:9999 /] /subsystem=modeshape/repository=sample/sequencer=delimited-text-sequencer:remove() {"outcome" => "success"}
To specify index storage, you first need to add the index storage resource to your configuration:
[standalone@localhost:9999 /] /subsystem=modeshape/repository=sample/configuration=index-storage:add() {"outcome" => "success"}
Once the index storage node is added, you can add the storage type with required/optional parameters:
[standalone@localhost:9999 /] /subsystem=modeshape/repository=sample/configuration=index-storage/storage-type=master-file-index-storage:add(connection-factory-jndi-name=conn-name,queue-jndi-name=queue-name, path=/somepath, source-path=/someotherpath) {"outcome" => "success"}
In the same way you specify index storage above, you first need to add the binary storage resource to your configuration:
[standalone@localhost:9999 /] /subsystem=modeshape/repository=sample/configuration=binary-storage:add() {"outcome" => "success"}
Once the binary storage node is added, you can add the storage type with required/optional parameters:
[standalone@localhost:9999 /] /subsystem=modeshape/repository=sample/configuration=binary-storage/storage-type=file-binary-storage:add(path=/somepath) {"outcome" => "success"}
Composite binary stores are different from the rest of the standard binary stores, because they can aggregate any number of standard binary stores. Therefore configuring them via CLI is a bit different.
First, you need to configure the composite binary store in similar fashion to any other binary store:
[standalone@localhost:9999 /] /subsystem=modeshape/repository=sample/configuration=binary-storage/storage-type=composite-binary-storage:add()
After this, you need to make sure that each nested store has a store-name property which is unique within the composite store and that the appropriate resource-container is used when adding the store.
Corresponding to each of the standard binary stores, the following resource-containers are available:
nested-storage-type-file - for file system binary stores
nested-storage-type-cache - for cache binary stores
nested-storage-type-db - for database binary stores
nested-storage-type-custom - for custom (user defined) binary stores
For example, if you wanted to add a file system binary store to a composite store, you would run:
[standalone@localhost:9999 /] /subsystem=modeshape/repository=sample/configuration=binary-storage/storage-type=composite-binary-storage/nested-storage-type-file=filesystem1:add(store-name=filesystem1, path="/somepath")
If you wanted to remove this store, you would run:
[standalone@localhost:9999 /] /subsystem=modeshape/repository=sample/configuration=binary-storage/storage-type=composite-binary-storage/nested-storage-type-file=filesystem1:remove()
You can use the CLI to dynamically add and remove custom authentication and authorization providers. For example, if your org.modeshape.jcr.security.AuthorizationProvider implementation were named "org.example.MyAuthProvider" and were added to a new "org.example.auth" module, then the following command would add this provider to the "sample" repository:
[standalone@localhost:9999 /] /subsystem=modeshape/repository=sample/authenticator=custom:add(classname="org.example.MyAuthProvider", module="org.example.auth") {"outcome" => "success"} [standalone@localhost:9999 /] /subsystem=modeshape/repository=sample/authenticator=jaas:read-resource() { "outcome" => "success", "result" => { "classname" => "org.modeshape.jcr.security.JaasProvider", "module" => "org.modeshape", "properties" => undefined } }
To remove an authentication provider, simply invoke the "remove" operation on the appropriate item:
[standalone@localhost:9999 /] /subsystem=modeshape/repository=sample/authenticator=custom:remove() {"outcome" => "success"}
ModeShape can set instance-level fields on the provider instances. For example, you might want to set the "auth-domain" field on the MyAuthProvider instance to the String value "global". To do this, simply add them via the "properties" parameter (which is a list of documents that each contain a single name-value pair):
[standalone@localhost:9999 /] /subsystem=modeshape/repository=sample/authenticator=custom:add(classname="org.example.MyAuthProvider", module="org.example.auth", properties=[ {"foo"=>"bar"}, {"baz"=>"bam"} ] ) {"outcome" => "success"} /subsystem=modeshape/repository=sample/authenticator=custom:read-resource() { "outcome" => "success", "result" => { "classname" => "org.example.MyAuthProvider", "module" => "org.example.auth", "properties" => [ {"foo" => "bar"}, {"baz" => "bam"} ] } }
First, you need to add the driver:
[standalone@localhost:9999 /] /subsystem=datasources/jdbc-driver=modeshape-driver:add(driver-name="modeshape-driver", driver-module-name="org.modeshape.jdbc", driver-class-name="org.modeshape.jdbc.LocalJcrDriver") {"outcome" => "success"}
Then, the actual datasource:
[standalone@localhost:9999 /] /subsystem=datasources/data-source="java:/datasources/ModeShapeDS":add(jndi-name="java:/datasources/ModeShapeDS",driver-name="modeshape-driver",connection-url="jdbc:jcr:jndi:jcr?repositoryName=artifacts",user-name="admin",password="admin") {"outcome" => "success"}
To enable federation, one or more external sources can be added to an existing repository.
The following example show how using the CLI an external file system source (via the FileSytemConnector) can be linked to the sample repository:
[standalone@localhost:9999 /] /subsystem=modeshape/repository=sample/source=fsSource:add(classname="org.modeshape.connector.filesystem.FileSystemConnector",properties=[{"directoryPath"=>"."}], readonly="true", projections=["default:/projection1 => /"], cacheTtlSeconds="1") {"outcome" => "success"} [standalone@localhost:9999 /] /subsystem=modeshape/repository=sample/source=fsSource:read-resource() { "outcome" => "success", "result" => { "cacheTtlSeconds" => "1", "classname" => "org.modeshape.connector.filesystem.FileSystemConnector", "module" => undefined, "projections" => ["default:/projection1 => /"], "properties" => [{"directoryPath" => "."}], "queryable" => undefined, "readonly" => "true" } }
Notice that there are several attributes that can be specified when adding an external source:
classname (mandatory) - the fully qualified name of the Connector class which allows content to be retrieved and written to that external source
module (optional) - the name of the EAP module where the above class can be found
projections (optional) - a list of projection expressions representing predefined projection paths for the source; projections can either be defined here or programmatically using the FederationManager.createProjection(...) method.
queryable (optional) - a flag indicating if the content exposed from the external source should be indexed by the repository or not. By default, all content is queryable.
readonly (optional) - a flag indicating if only reads or both reads and writes are possible on the source
cacheTtlSeconds (optional) - the number of seconds any given node from the external source is to be held in the cache of the corresponding workspace
properties (optional) - an array of key - value pairs which allow any custom attributes to be passed down on the Connector implementation class.
To remove an external source, just invoke remove on that source:
[standalone@localhost:9999 /] /subsystem=modeshape/repository=sample/source=fsSource:remove() {"outcome" => "success"}
You can combine all these commands (except for the initial /extension=org.modeshape:add() command) into a batch operation:
[standalone@localhost:9999 /] /extension=org.modeshape:add() {"outcome" => "success"} [standalone@localhost:9999 /] batch [standalone@localhost:9999 / #] (paste the commands here) [standalone@localhost:9999 / #] run-batch The batch executed successfully.
Batches can be stashed or edited before they are run, and multiple commands can be easily pasted into a batch.
Before configuring ModeShape to run in a cluster, make sure the JGroups subsystem is present in the EAP configuration.
After that, the following parts need configuring:
1) Replicated Infinispan caches for the repository store and the binary store:
/subsystem=infinispan/cache-container=modeshape:add(module="org.modeshape") /subsystem=infinispan/cache-container=modeshape/transport=TRANSPORT:add(lock-timeout="60000") /subsystem=infinispan/cache-container=modeshape/replicated-cache=sample:add(mode="SYNC", batching="true") /subsystem=infinispan/cache-container=modeshape/replicated-cache=sample/transaction=TRANSACTION:add(mode=NON_XA) /subsystem=infinispan/cache-container=modeshape/replicated-cache=sample/file-store=FILE_STORE:add(path="modeshape/store/sample-${jboss.node.name}",relative-to="jboss.server.data.dir",passivation=false,purge=false) /subsystem=infinispan/cache-container=modeshape-binary-store:add(module="org.modeshape") /subsystem=infinispan/cache-container=modeshape-binary-store/transport=TRANSPORT:add(lock-timeout="60000") /subsystem=infinispan/cache-container=modeshape-binary-store/replicated-cache=sample-binary-data:add(mode="SYNC", batching="true") /subsystem=infinispan/cache-container=modeshape-binary-store/replicated-cache=sample-binary-data/transaction=TRANSACTION:add(mode=NON_XA) /subsystem=infinispan/cache-container=modeshape-binary-store/replicated-cache=sample-binary-data/file-store=FILE_STORE:add(path="modeshape/binary-store/sample-data-${jboss.node.name}",relative-to="jboss.server.data.dir",passivation=false,purge=false) /subsystem=infinispan/cache-container=modeshape-binary-store/replicated-cache=sample-binary-metadata:add(mode="SYNC", batching="true") /subsystem=infinispan/cache-container=modeshape-binary-store/replicated-cache=sample-binary-metadata/transaction=TRANSACTION:add(mode=NON_XA) /subsystem=infinispan/cache-container=modeshape-binary-store/replicated-cache=sample-binary-metadata/file-store=FILE_STORE:add(path="modeshape/binary-store/sample-metadata-${jboss.node.name}",relative-to="jboss.server.data.dir",passivation=false,purge=false)
2) Main repository
/subsystem=modeshape/repository=sample:add(cache-container="modeshape",cache-name="sample",cluster-name="modeshape-sample",cluster-stack="tcp",security-domain="modeshape-security")
3) Indexing
/subsystem=modeshape/repository=sample/configuration=index-storage:add() /subsystem=modeshape/repository=sample/configuration=index-storage/storage-type=local-file-index-storage:add(path="modeshape/indexes/sample-indexes-${jboss.node.name}")
4) Binary Storage
/subsystem=modeshape/repository=sample/configuration=binary-storage:add() /subsystem=modeshape/repository=sample/configuration=binary-storage/storage-type=cache-binary-storage:add(data-cache-name="sample-binary-data", metadata-cache-name="sample-binary-metadata", cache-container="modeshape-binary-store")